/**
 * Created by PanJiaChen on 16/11/18.
 */

/**
 * Parse the time to string
 * @param {(Object|string|number)} time
 * @param {string} cFormat
 * @returns {string | null}
 */
export function parseTime(time, cFormat) {
  if (arguments.length === 0 || !time) {
    return null
  }
  const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
  let date
  if (typeof time === 'object') {
    date = time
  } else {
    if ((typeof time === 'string')) {
      if ((/^[0-9]+$/.test(time))) {
        // support "1548221490638"
        time = parseInt(time)
      } else {
        // support safari
        // https://stackoverflow.com/questions/4310953/invalid-date-in-safari
        time = time.replace(new RegExp(/-/gm), '/')
      }
    }

    if ((typeof time === 'number') && (time.toString().length === 10)) {
      time = time * 1000
    }
    date = new Date(time)
  }
  const formatObj = {
    y: date.getFullYear(),
    m: date.getMonth() + 1,
    d: date.getDate(),
    h: date.getHours(),
    i: date.getMinutes(),
    s: date.getSeconds(),
    a: date.getDay()
  }
  const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
    const value = formatObj[key]
    // Note: getDay() returns 0 on Sunday
    if (key === 'a') {
      return ['日', '一', '二', '三', '四', '五', '六'][value]
    }
    return value.toString().padStart(2, '0')
  })
  return time_str
}

/**
 * @param {number} time
 * @param {string} option
 * @returns {string}
 */
export function formatTime(time, option) {
  if (('' + time).length === 10) {
    time = parseInt(time) * 1000
  } else {
    time = +time
  }
  const d = new Date(time)
  const now = Date.now()

  const diff = (now - d) / 1000

  if (diff < 30) {
    return '刚刚'
  } else if (diff < 3600) {
    // less 1 hour
    return Math.ceil(diff / 60) + '分钟前'
  } else if (diff < 3600 * 24) {
    return Math.ceil(diff / 3600) + '小时前'
  } else if (diff < 3600 * 24 * 2) {
    return '1天前'
  }
  if (option) {
    return parseTime(time, option)
  } else {
    return (
      d.getMonth() +
      1 +
      '月' +
      d.getDate() +
      '日' +
      d.getHours() +
      '时' +
      d.getMinutes() +
      '分'
    )
  }
}

/**
 * @param {string} url
 * @returns {Object}
 */
export function param2Obj(url) {
  const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
  if (!search) {
    return {}
  }
  const obj = {}
  const searchArr = search.split('&')
  searchArr.forEach(v => {
    const index = v.indexOf('=')
    if (index !== -1) {
      const name = v.substring(0, index)
      const val = v.substring(index + 1, v.length)
      obj[name] = val
    }
  })
  return obj
}

/**
 * 如果传入的参数只有一个数组，求笛卡尔积结果
 * @param arr1 一维数组
 * @returns {Array}
 */
function descartes1(arr1) {
  // 返回结果，是一个二维数组
  var result = []
  var i = 0
  for (i = 0; i < arr1.length; i++) {
    var item1 = arr1[i]
    result.push([item1])
  }
  return result
}

/**
 * 如果传入的参数只有两个数组，求笛卡尔积结果
 * @param arr1 一维数组
 * @param arr2 一维数组
 * @returns {Array}
 */
function descartes2(arr1, arr2) {
  // 返回结果，是一个二维数组
  var result = []
  var i = 0, j = 0
  for (i = 0; i < arr1.length; i++) {
    var item1 = arr1[i]
    for (j = 0; j < arr2.length; j++) {
      var item2 = arr2[j]
      result.push([item1, item2])
    }
  }
  return result
}

/**
 *
 * @param arr2D 二维数组
 * @param arr1D 一维数组
 * @returns {Array}
 */
// eslint-disable-next-line no-unused-vars
function descartes2DAnd1D(arr2D, arr1D) {
  var i = 0, j = 0
  // 返回结果，是一个二维数组
  var result = []

  for (i = 0; i < arr2D.length; i++) {
    var arrOf2D = arr2D[i]
    for (j = 0; j < arr1D.length; j++) {
      var item1D = arr1D[j]
      result.push(arrOf2D.concat(item1D))
    }
  }

  return result
}

function descartes3(list) {
  var listLength = list.length
  var i = 0, j = 0
  // 返回结果，是一个二维数组
  var result = []
  // 为了便于观察，采用这种顺序
  var arr2D = descartes2(list[0], list[1])
  for (i = 2; i < listLength; i++) {
    var arrOfList = list[i]
    arr2D = descartes2DAnd1D(arr2D, arrOfList)
  }
  return arr2D
}

function allSort(arr) {
  for (let i = 0; i < arr.length; i++) {
    if (Array.isArray(arr[i])) {
      arr[i] = arr[i].sort()
    }
  }
  arr = arr.sort()
  return arr
}

export function descartes(list) {
  list = allSort(list)
  if (!list) {
    return []
  }
  if (list.length <= 0) {
    return []
  }
  if (list.length == 1) {
    return descartes1(list[0])
  }
  if (list.length == 2) {
    return descartes2(list[0], list[1])
  }
  if (list.length >= 3) {
    return descartes3(list)
  }
}

export function ksort(vm, inputArr, sort_flags) {
  //  discuss at: http://phpjs.org/functions/ksort/
  // original by: GeekFG (http://geekfg.blogspot.com)
  // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  // improved by: Brett Zamir (http://brett-zamir.me)
  //        note: The examples are correct, this is a new way
  //        note: This function deviates from PHP in returning a copy of the array instead
  //        note: of acting by reference and returning true; this was necessary because
  //        note: IE does not allow deleting and re-adding of properties without caching
  //        note: of property position; you can set the ini of "phpjs.strictForIn" to true to
  //        note: get the PHP behavior, but use this only if you are in an environment
  //        note: such as Firefox extensions where for-in iteration order is fixed and true
  //        note: property deletion is supported. Note that we intend to implement the PHP
  //        note: behavior by default if IE ever does allow it; only gives shallow copy since
  //        note: is by reference in PHP anyways
  //        note: Since JS objects' keys are always strings, and (the
  //        note: default) SORT_REGULAR flag distinguishes by key type,
  //        note: if the content is a numeric string, we treat the
  //        note: "original type" as numeric.
  //  depends on: i18n_loc_get_default
  //  depends on: strnatcmp
  //   example 1: data = {d: 'lemon', a: 'orange', b: 'banana', c: 'apple'};
  //   example 1: data = ksort(data);
  //   example 1: $result = data
  //   returns 1: {a: 'orange', b: 'banana', c: 'apple', d: 'lemon'}
  //   example 2: ini_set('phpjs.strictForIn', true);
  //   example 2: data = {2: 'van', 3: 'Zonneveld', 1: 'Kevin'};
  //   example 2: ksort(data);
  //   example 2: $result = data
  //   returns 2: {1: 'Kevin', 2: 'van', 3: 'Zonneveld'}

  var tmp_arr = {},
    keys = [],
    sorter, i, k, that = vm,
    strictForIn = false,
    populateArr = {}

  switch (sort_flags) {
    case 'SORT_STRING':
      // compare items as strings
      sorter = function(a, b) {
        return that.strnatcmp(a, b)
      }
      break
    case 'SORT_LOCALE_STRING':
      // compare items as strings, original by the current locale (set with  i18n_loc_set_default() as of PHP6)
      var loc = vm.i18n_loc_get_default()
      sorter = vm.php_js.i18nLocales[loc].sorting
      break
    case 'SORT_NUMERIC':
      // compare items numerically
      sorter = function(a, b) {
        return ((a + 0) - (b + 0))
      }
      break
    // case 'SORT_REGULAR': // compare items normally (don't change types)
    default:
      sorter = function(a, b) {
        var aFloat = parseFloat(a),
          bFloat = parseFloat(b),
          aNumeric = aFloat + '' === a,
          bNumeric = bFloat + '' === b
        if (aNumeric && bNumeric) {
          return aFloat > bFloat ? 1 : aFloat < bFloat ? -1 : 0
        } else if (aNumeric && !bNumeric) {
          return 1
        } else if (!aNumeric && bNumeric) {
          return -1
        }
        return a > b ? 1 : a < b ? -1 : 0
      }
      break
  }

  // Make a list of key names
  for (k in inputArr) {
    if (inputArr.hasOwnProperty(k)) {
      keys.push(k)
    }
  }
  keys.sort(sorter)

  // BEGIN REDUNDANT
  vm.php_js = vm.php_js || {}
  vm.php_js.ini = vm.php_js.ini || {}
  // END REDUNDANT
  strictForIn = vm.php_js.ini['phpjs.strictForIn'] && vm.php_js.ini['phpjs.strictForIn'].local_value && vm.php_js
    .ini['phpjs.strictForIn'].local_value !== 'off'
  populateArr = strictForIn ? inputArr : populateArr

  // Rebuild array with sorted key names
  for (i = 0; i < keys.length; i++) {
    k = keys[i]
    tmp_arr[k] = inputArr[k]
    if (strictForIn) {
      delete inputArr[k]
    }
  }
  for (i in tmp_arr) {
    if (tmp_arr.hasOwnProperty(i)) {
      populateArr[i] = tmp_arr[i]
    }
  }

  return strictForIn || populateArr
}
